package org.springblade.modules.admin.controller;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springblade.core.mp.base.BaseEntity;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.admin.dto.sugar.SugarSearchDTO;
import org.springblade.modules.admin.entity.Elevator;
import org.springblade.modules.admin.entity.ElevatorPrincipalDept;
import org.springblade.modules.admin.entity.MaintainPlanContent;
import org.springblade.modules.admin.enums.MaintainPlanContentEnum;
import org.springblade.modules.admin.enums.TaskStatusEnum;
import org.springblade.modules.admin.enums.WorkOrderTypeEnum;
import org.springblade.modules.admin.service.*;
import org.springblade.modules.admin.vo.*;
import org.springblade.modules.admin.vo.contract.ContractStatisticVo;
import org.springblade.modules.admin.vo.sugar.MalfunctionScreenVO;
import org.springblade.modules.system.service.IDeptService;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 新维修大屏 Controller Sharry部分
 *
 * @author Sharry
 * @since 2023-10-19
 */
@RestController
@AllArgsConstructor
@RequestMapping("/new/repair/screen")
@Api(value = "/new/repair/screen", tags = "新维修大屏项目-电梯-报障")
public class NewRepairScreenController {

	private final BuildingService buildingService;

	private final ElevatorService elevatorService;

	private final IBuildingContractPlusService buildingContractPlusService;

	private final IMaintainPlanContentService maintainPlanContentService;
	private final IDeptService deptService;
	private final ElevatorPrincipalDeptService elevatorPrincipalDeptService;

	/**
	 * 当前租户项目-电梯统计
	 */
	@GetMapping("/building")
	@ApiOperationSupport(order = 10)
	@ApiOperation(value = "当前租户项目-电梯统计", notes = "没有参数查询全部")
	public R<BuildingElevatorCountVO> getBuildingElevatorCounts() {
		BuildingElevatorCountVO result = buildingService.getBuildingElevatorCounts();
		return R.data(result);
	}

	/**
	 * 当前租户电梯统计
	 */
	@PostMapping("/elevator")
	@ApiOperationSupport(order = 11)
	@ApiOperation(value = "当前租户电梯统计", notes = "传入时间区间")
	public R<NewRepairScreenElevatorCountVO> getBuildingElevatorCounts(@RequestBody SugarSearchDTO searchDTO) {
		// 格式化日期字符串为Date对象
		Map<String, Date> stringDateMap = dateFormatMethod(searchDTO.getStartTime(), searchDTO.getEndTime());
		Date beginTimeDate = stringDateMap.get("beginTimeDate");
		Date endTimeDate = stringDateMap.get("endTimeDate");
		NewRepairScreenElevatorCountVO result = new NewRepairScreenElevatorCountVO();

		List<Long> deptIds = deptService.selectDeptAndAllChildIds(searchDTO.getDeptIds());
		List<ElevatorPrincipalDept> elevatorDepts = elevatorPrincipalDeptService.list(Wrappers.<ElevatorPrincipalDept>lambdaQuery().in(ElevatorPrincipalDept::getDeptId,deptIds));
		List<Long> elevatorIds = elevatorDepts.stream().map(ElevatorPrincipalDept::getElevatorId).distinct().collect(Collectors.toList());
		List<Elevator> sugarMapEleList = elevatorService.getSugarMapEleList();
		sugarMapEleList = sugarMapEleList.stream().filter(e -> elevatorIds.contains(e.getId())).collect(Collectors.toList());

		// 1. 电梯总数
		int elevatorNum = sugarMapEleList.size();
		if (elevatorNum == 0) {
			return R.data(new NewRepairScreenElevatorCountVO());
		}
		// 2. 维保电梯总数
		ContractStatisticVo contractStatisticInfo = buildingContractPlusService.getContractStatisticInfo();
		// 3. 故障电梯数、重复故障电梯数
		Integer repairElevator = Func.isEmpty(elevatorIds) ? 0 : maintainPlanContentService.getRepairElevatorCount(beginTimeDate, endTimeDate,elevatorIds);
		Integer veryMuchProblemElevatorCount = Func.isEmpty(elevatorIds) ? 0 : maintainPlanContentService.getVeryMuchProblemElevatorCount(beginTimeDate, endTimeDate,elevatorIds);
		/**
		 *	正常电梯: 电梯总数-故障电梯数
		 *	非重复电梯数: 故障电梯数-重复电梯数
		 *	故障率: 故障电梯数 / 电梯总数         （旧）
		 *	重复故障率: 重复故障电梯数 / 电梯总数  （旧）
		 *
		 *  2023-11-03  故障率与重复故障率改为 与 强哥的
		 *  /admin/malfunction/screen/detail/data
		 *  相同计算方式，时间维度修改
		 */
		// 规定天数内的维修单数
		List<MaintainPlanContentVO> tasks = maintainPlanContentService.selectMalfunctionListInMonthPlus(beginTimeDate, endTimeDate);
		// 规定天数内的电梯数量
		List<ElevatorEffectedVO> elevatorEffectedList = maintainPlanContentService.selectElevatorEffectedListByDate(beginTimeDate, endTimeDate);
		if(Func.isNotEmpty(elevatorIds)){
			tasks = tasks.stream().filter(e -> elevatorIds.contains(e.getElevatorId())).collect(Collectors.toList());
			elevatorEffectedList = elevatorEffectedList.stream().filter(e -> elevatorIds.contains(e.getElevatorId())).collect(Collectors.toList());
		}else {
			tasks = new ArrayList<>();
			elevatorEffectedList = new ArrayList<>();
		}

		MalfunctionScreenVO malfunctionScreenVO = handleMalfunctionScreenDataBetweenDay(tasks, elevatorEffectedList,searchDTO.getBetweenDay());
		String eleFaultRatio = malfunctionScreenVO.getEleFaultRatio();
		String eleRepeatFaultRatio = malfunctionScreenVO.getEleRepeatFaultRatio();
		result.setRepairRatePercentage(eleFaultRatio);
		result.setMuchProblemRatePercentage(eleRepeatFaultRatio);
		result.setEleFaultRatioMonth(malfunctionScreenVO.getEleFaultRatioMonth());
		result.setEleRepeatFaultRatioMonth(malfunctionScreenVO.getEleRepeatFaultRatioMonth());

		Integer noProblemElevatorCount = elevatorNum - repairElevator;
		Integer singleProblemElevatorCount = repairElevator - veryMuchProblemElevatorCount;

		// 赋值并返回：
		// 电梯总数
		result.setElevatorNum(elevatorNum);
		// 维保电梯
		result.setEnContractElevatorCount(contractStatisticInfo.getEnContractElevatorCount());
		// 故障电梯
		result.setRepairElevator(repairElevator);
		// 正常电梯
		result.setNoProblemElevatorCount(noProblemElevatorCount);
		// 重复故障电梯
		result.setVeryMuchProblemElevatorCount(veryMuchProblemElevatorCount);
		// 非重复故障梯
		result.setSingleProblemElevatorCount(singleProblemElevatorCount);

		// 两个率百分比
//		result.setRepairRatePercentage(repairRate.multiply(new BigDecimal(100)).setScale(1, RoundingMode.HALF_UP) + "%");
//		result.setMuchProblemRatePercentage(muchProblemRate.multiply(new BigDecimal(100)).setScale(1, RoundingMode.HALF_UP) + "%");

		// 故障率
//		BigDecimal repairRate = new BigDecimal(repairElevator)
//			.divide(new BigDecimal(elevatorNum == 0 ? 1 : elevatorNum), 5, RoundingMode.HALF_UP);
		// 故障率
//		result.setRepairRate(repairRate);
		// 重复故障率
//		BigDecimal muchProblemRate = new BigDecimal(veryMuchProblemElevatorCount)
//			.divide(new BigDecimal(repairElevator.equals(0) ? 1 : repairElevator), 5, RoundingMode.HALF_UP);
		// 重复故障率
// 	    result.setMuchProblemRate(muchProblemRate);
		return R.data(result);
	}

	/**
	 * 当前租户报障统计
	 */
	@PostMapping("/plan")
	@ApiOperationSupport(order = 12)
	@ApiOperation(value = "当前租户报障统计", notes = "传入时间区间")
	public R<Map<String, Integer>> getPlanContents(@RequestBody SugarSearchDTO sugarSearchDTO) {
		Map<String, Date> stringDateMap = dateFormatMethod(sugarSearchDTO.getStartTime(), sugarSearchDTO.getEndTime());
		Date beginTimeDate = stringDateMap.get("beginTimeDate");
		Date endTimeDate = stringDateMap.get("endTimeDate");

		List<Long> deptIds = deptService.selectDeptAndAllChildIds(sugarSearchDTO.getDeptIds());
		List<ElevatorPrincipalDept> elevatorDepts = elevatorPrincipalDeptService.list(Wrappers.<ElevatorPrincipalDept>lambdaQuery().in(ElevatorPrincipalDept::getDeptId,deptIds));
		List<Long> elevatorIds = elevatorDepts.stream().map(ElevatorPrincipalDept::getElevatorId).collect(Collectors.toList());
		// 获取时间区间内的工单总数
		List<MaintainPlanContent> allList = maintainPlanContentService.listWxPlan(beginTimeDate,endTimeDate);
		allList = allList.stream().filter(e -> elevatorIds.contains(e.getElevatorId())).collect(Collectors.toList());
		Map<String, Integer> result = new HashMap<>(5);
		if (Func.isNotEmpty(allList)) {
			allList = allList.stream().filter(e -> e.getWorkOrderType().equals(WorkOrderTypeEnum.CLIENT.getId())).collect(Collectors.toList());
			if(Func.isNotEmpty(allList)){
				// 总数
				String all = "all";
				int allSize = allList.size();
				result.put(all, allSize);
				// 待指派工单数
				String prepareToSend = "prepareToSend";
				long prepareToSendCount = allList.stream().filter(f -> f.getStatus().equals(TaskStatusEnum.WX_ALLOCATION.getStatus())).count();
				result.put(prepareToSend, (int) prepareToSendCount);
				// 待审核工单数
				String prepareToExamine = "prepareToExamine";
				long prepareToExamineCount = allList.stream().filter(f -> f.getStatus().equals(TaskStatusEnum.WX_PENDING.getStatus())).count();
				result.put(prepareToExamine, (int) prepareToExamineCount);
				// 审核通过工单数
				String examinePass = "examinePass";
				List<Integer> passStatus = new ArrayList<>();
				passStatus.add(TaskStatusEnum.WX_TO_START.getStatus());
				passStatus.add(TaskStatusEnum.WX_UNDER_WAY.getStatus());
				passStatus.add(TaskStatusEnum.WX_SIGN_FINISH.getStatus());
				passStatus.add(TaskStatusEnum.WX_CHECK_PASS_CLOSED.getStatus());
				long examinePassCount = allList.stream().filter(f -> passStatus.contains(f.getStatus())).count();
				result.put(examinePass, (int) examinePassCount);
				// 审核不通过工单数
				String noPass = "noPass";
				long noPassCount = allList.stream().filter(f -> f.getStatus().equals(TaskStatusEnum.WX_TURN_DOWN.getStatus())).count();
				result.put(noPass, (int) noPassCount);
				// 撤回工单数
				String rollBack = "rollBack";
				long rollBackCount = allList.stream().filter(f -> f.getStatus().equals(TaskStatusEnum.WX_CLOSED.getStatus())).count();
				result.put(rollBack, (int) rollBackCount);
			}
		}
		return R.data(result);
	}

	@GetMapping("/source")
	@ApiOperationSupport(order = 13)
	@ApiOperation(value = "报障来源统计", notes = "传入时间区间")
	public R<List<NewRepairScreenSourceVO>> getPlanSources(@RequestParam("beginTime") String beginTimeString,
														   @RequestParam("endTime") String endTimeString) {
		Map<String, Date> stringDateMap = dateFormatMethod(beginTimeString, endTimeString);
		Date beginTimeDate = stringDateMap.get("beginTimeDate");
		Date endTimeDate = stringDateMap.get("endTimeDate");
		List<NewRepairScreenSourceVO> result = maintainPlanContentService.getPlanSources(beginTimeDate, endTimeDate);
		return R.data(result);
	}

	public Map<String, Date> dateFormatMethod(String beginTimeString, String endTimeString) {
		Map<String, Date> result = new HashMap<>(2);
		// 格式化日期字符串为Date对象
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		LocalDateTime beginTime = LocalDateTime.parse(beginTimeString, formatter);
		LocalDateTime endTime = LocalDateTime.parse(endTimeString, formatter);
		Date beginTimeDate = Date.from(beginTime.toInstant(ZoneOffset.UTC));
		Date endTimeDate = Date.from(endTime.toInstant(ZoneOffset.UTC));
		result.put("beginTimeDate", beginTimeDate);
		result.put("endTimeDate", endTimeDate);
		return result;
	}

	/**
	 * 2023-11-03 需求变更。
	 * 复用强哥的维修方法
	 * 封装数据大屏维修数据
	 *
	 * @param tasks                任务list
	 * @param elevatorEffectedList 有效梯list
	 * @return 结果
	 */
	private MalfunctionScreenVO handleMalfunctionScreenDataBetweenDay(List<MaintainPlanContentVO> tasks, List<ElevatorEffectedVO> elevatorEffectedList,Integer betweenDay) {
		MalfunctionScreenVO malfunctionScreenVO = new MalfunctionScreenVO();
		long applyRepairTotal = tasks.stream().filter(t -> TaskStatusEnum.WX_CLOSED.getStatus() != t.getStatus() || TaskStatusEnum.WX_TURN_DOWN.getStatus() != t.getStatus()).count();
		malfunctionScreenVO.setApplyRepairTotal(applyRepairTotal);

		// 新增维修任务 (维修任务状态为【待开始】/【进行中】/【已完成】的维修任务工单总数)
		List<Integer> repairTaskStatus = Arrays.asList(TaskStatusEnum.WX_TO_START.getStatus(), TaskStatusEnum.WX_UNDER_WAY.getStatus(), TaskStatusEnum.WX_SIGN_FINISH.getStatus());
		long repairTaskTotal = tasks.stream().filter(t -> repairTaskStatus.contains(t.getStatus())).count();
		malfunctionScreenVO.setRepairTaskTotal(repairTaskTotal);

		// 有效梯
		long elevatorTotal = Func.isEmpty(elevatorEffectedList) ? 0 : elevatorEffectedList.stream().map(t -> t.getElevatorId()).distinct().count();
		// 第一次维修任务数
		long firstPlanTotal = tasks.stream().filter(t -> repairTaskStatus.contains(t.getStatus())).map(t -> t.getElevatorId()).distinct().count();
		// 重复故障任务数
		long repeatPlanTotal = repairTaskTotal - firstPlanTotal;
		if (elevatorTotal > 0) {
			// 梯故障率 = 故障电梯总数(新增维修任务)/生效电梯数
			BigDecimal eleFaultRatio = new BigDecimal(repairTaskTotal).divide(new BigDecimal(elevatorTotal), 3, BigDecimal.ROUND_HALF_UP);
			malfunctionScreenVO.setEleFaultRatio(eleFaultRatio);
			malfunctionScreenVO.setEleFaultRatioMonth(eleFaultRatio.multiply(BigDecimal.valueOf(30)).divide(BigDecimal.valueOf(betweenDay),3,RoundingMode.HALF_UP));
			// 重复故障率 (重复故障率 = 重复故障任务总数/生效电梯数)
			BigDecimal eleRepeatFaultRatio = new BigDecimal(repeatPlanTotal).divide(new BigDecimal(elevatorTotal), 3, BigDecimal.ROUND_HALF_UP);
			malfunctionScreenVO.setEleRepeatFaultRatio(eleRepeatFaultRatio);
			malfunctionScreenVO.setEleRepeatFaultRatioMonth(eleRepeatFaultRatio.multiply(BigDecimal.valueOf(30)).divide(BigDecimal.valueOf(betweenDay),3,RoundingMode.HALF_UP));
		}

		return malfunctionScreenVO;
	}


}
